#include "mq_channel.hpp"

namespace mq{

class Connection{
private:
    //信道管理句柄
    mq::ChannelManager::ptr _channels;

    mq::VirtualHost::ptr _host;//虚拟机管理句柄
    mq::ConsumerManager::ptr _cmp;//消费者管理句柄
    ProtobufCodecPtr _codec;//协议处理句柄
    muduo::net::TcpConnectionPtr _conn;//连接句柄
    mq::threadpool::ptr _pool;//任务池（线程池）
public:
    using ptr = std::shared_ptr<Connection>;

    Connection(const mq::VirtualHost::ptr& host,
            const mq::ConsumerManager::ptr& cmp,
            const ProtobufCodecPtr& codec,
            const muduo::net::TcpConnectionPtr& conn,
            const mq::threadpool::ptr pool):_host(host),
                _cmp(cmp),_codec(codec),_conn(conn),_pool(pool),
                _channels(std::make_shared<ChannelManager>()){}

    void openChannel(const openChannelRequestPtr& req){
        //判断是否已经存在信道
        bool ret = _channels->openChannel(req->cid(),_host,_cmp,_codec,_conn,_pool);
        if(ret == false){
            DLOG("创建信道的时候，信道 id 重复了!")
            return basicResponse(false,req->rid(),req->cid());
        }
        // DLOG("创建信道成功！信道id：%s",req->cid());

        return basicResponse(true,req->rid(),req->cid());
    }

    void closeChannel(const closeChannelRequestPtr& req){
        _channels->closeChannel(req->cid());
        return basicResponse(true,req->rid(),req->cid());
    }

    Channel::ptr getChannel(const std::string &cid){
        return _channels->getChannel(cid);
    }

private:
    void basicResponse(bool ok,const std::string& rid,const std::string& cid){
        //class basicCommonResponse final : public ::PROTOBUF_NAMESPACE_ID::Message
        mq::basicCommonResponse resp;//通用响应
        resp.set_ok(ok);
        resp.set_rid(rid);
        resp.set_cid(cid);
        //void send(const muduo::net::TcpConnectionPtr& conn, const google::protobuf::Message& message)
        _codec->send(_conn,resp);//basicCommonResponse类型继承Message类型
    }
};

class ConnectionManager{
private:
    //锁
    std::mutex _mutex;
    //hash: 连接 ： connection对象
    std::unordered_map<muduo::net::TcpConnectionPtr,Connection::ptr> _conns;
    // Tcp连接 : 连接对象(多个信道)
public:
    using ptr = std::shared_ptr<ConnectionManager>;
    
    ConnectionManager(){}
    //增加连接
    void newConnection(const mq::VirtualHost::ptr& host,
            const mq::ConsumerManager::ptr& cmp,
            const ProtobufCodecPtr& codec,
            const muduo::net::TcpConnectionPtr& conn,
            const mq::threadpool::ptr pool){

        std::unique_lock<std::mutex> lock(_mutex);
        //判断连接是否已经存在
        auto it = _conns.find(conn);
        if(it != _conns.end()){
            return ;
        }
        //创建连接
        Connection::ptr self_conn = std::make_shared<Connection>(host,cmp,codec,conn,pool);
        //插入map中
        _conns.insert(std::make_pair(conn,self_conn));
    }

    void delConnection(const muduo::net::TcpConnectionPtr& conn){
        std::unique_lock<std::mutex> lock(_mutex);
        _conns.erase(conn);
    }

    Connection::ptr getConnection(const muduo::net::TcpConnectionPtr& conn){
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _conns.find(conn);
        if(it == _conns.end()){
            return Connection::ptr();
        }
        return it->second;
    }
};
}